package cn.cdm.config;

import cn.cdm.domain.MiaoshaUser;
import cn.cdm.service.MiaoshaUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 为什么使用UserArgumentResolver：每个Controller开始，先调用tokenUtils.getUserByToken(token)，不够优雅。
 * 当客户端传递token过来后，该supportsParameter方法不会执行了
 *
 * Web层的拦截处理类：
 *   在请求对象交给Controller层之前，判断请求对象中是否包含MiaoshaUser对象；
 *   若包含，则获取cookie信息，并根据cookie中的token查询对应的秒杀用户对象信息；若不包含MiaoshaUser对象，则直接返回。
 */
@Slf4j
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {

	@Autowired
    MiaoshaUserService userService;

	// 用于判定是否需要处理该参数分解，返回true为需要，并会去调用下面的方法resolveArgument
	public boolean supportsParameter(MethodParameter parameter) {
		Class<?> clazz = parameter.getParameterType();
		log.info("解析参数类型：{}", clazz);
		return clazz == MiaoshaUser.class;
	}

	//真正用于处理参数分解的方法，返回的Object就是controller方法上的形参对象。
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
								  WebDataBinderFactory binderFactory) throws Exception {
		HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
		HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
		//有的手机端将cookie放到参数内传输，所以需要先判断参数
		String paramToken = request.getParameter(MiaoshaUserService.COOKI_NAME_TOKEN); // 获取手机端中的cookie参数
		String cookieToken = getCookieValue(request, MiaoshaUserService.COOKI_NAME_TOKEN);
		if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) {
			return null;
		}
		String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
		// 根据sessionId（也就是token）作为键，来获取Redis中的值
		return userService.getByToken(response, token);
	}

	//返回token对应的cookie值。根据cookie名称查找对应的cookie值
	private String getCookieValue(HttpServletRequest request, String cookieName) {
		Cookie[]  cookies = request.getCookies();

		if(cookies != null && cookies.length > 0) {
			for(Cookie cookie : cookies) {
				// 先根据cookieName，判断是哪个用户的cookie；然后根据cookie.getValue()获取sessionId(也就是token)
				if(cookie.getName().equals(cookieName)) {
					return cookie.getValue();
				}
			}
		}
		return null;
	}

}
